/****************************************************************************

	COPYRIGHT(C) MAXSI SOFTWARE, JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010

    This file is part of Maxsi Engine.

    Maxsi Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Maxsi Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	*/ #include "MaxsiEngineContributors.h" /*

	If you modify this file, please enter your name below and provide contact
	information in MaxsiEngineContributors.h. For more information please see
	MaxsiEngineContributors.h.
	
	Contributors to this file:

	- Jonas 'Sortie' Termansen
	- [your name here]

	MaxsiEngine.dll
	A linkable version of Maxsi Engine.

	MaxsiIO.cpp
	A Simple Flexible Async I/O System.

****************************************************************************/

#include "MaxsiEngine.h"

#if !defined(ME_IODisabled) || defined(ME_IOEnabled)
namespace MaxsiEngine
{
	ME_Component::ME_Component()
	{
	}

	ME_Component::~ME_Component()
	{
	}

	int	ME_INT::Get()
	{
		return Value;
	}

	void ME_INT::Set(int NewValue)
	{
		Value	=	NewValue;
	}

	void ME_INT::operator=	(int NewValue)
	{
		Set(NewValue);
	}
	int	ME_INT::operator=	( const ME_INT &Val )
	{
		return Val.Value;
	}
	void ME_INT::operator|=	(int NewValue)
	{
		Set(Value | NewValue);
	}
	void ME_INT::operator&=	(int NewValue)
	{
		Set(Value & NewValue);
	}
	ME_INT::operator int() const
	{
		return Value;
	}

	ME_IOConnectionPointer::operator ME_IOConnection*()
	{
		return IOConnection;
	}
	ME_IOConnectionPointer::operator ME_IOConnection*() const
	{
		return IOConnection;
	}
	ME_IOConnectionPointer::operator ME_IOConnectionPointer*() const
	{
		return (ME_IOConnectionPointer*)this;
	}
	bool ME_IOConnectionPointer::operator !() const
	{
		return !IOConnection;
	}
	bool ME_IOConnectionPointer::operator==( ME_IOConnectionPointer &val )
	{
		return IOConnection == val.IOConnection;
	}
	bool ME_IOConnectionPointer::operator==( ME_IOConnectionPointer* val ) const
	{
		return IOConnection == val->IOConnection;
	}
	bool ME_IOConnectionPointer::operator!=( ME_IOConnectionPointer* val ) const
	{
		return IOConnection != val->IOConnection;
	}
	const	ME_IOConnectionPointer&	ME_IOConnectionPointer::operator=( const ME_IOConnection *Val )
	{
		ME_DONT_COMPILE_RELEASE_BUILD();
		// Todo: should we also reset other values here?
		// Todo: I don't think this connection does what it is supposed to do.
		IOConnection = (ME_IOConnection*)Val;
		return *this;
	}
	ME_IOConnection*	ME_IOConnectionPointer::operator->() const
	{
		return IOConnection;
	}
	ME_IOConnection*	ME_IOConnectionPointer::operator->()
	{
		return IOConnection;
	}


	ME_IOConnectionPointer::ME_IOConnectionPointer()
	{
		Flags			=	0;
		IOConnection	=	NULL;
		Other			=	NULL;
		Speed			=	0;
		Total			=	0;
	}
	
	SIZE_T ME_IOConnectionPointer::GetBytesAvailable()
	{
		ME_TODO("Implement this!");
		return 0;
	}

	ME_IOConnectionContext::ME_IOConnectionContext()
	{
		Buffer			=	NULL;
	}

	ME_IOConnectionContext::~ME_IOConnectionContext()
	{
		if ( Buffer ) { delete[] Buffer; }
	}

	bool ME_IOConnectionContext::operator==( const ME_Buffer* Other )
	{ 
		return ( Buffer == Other );
	}

	bool ME_IOConnectionContext::AddConnection(ME_IOConnection* Connection)
	{
		ME_TODO("Implement this!");
		return false;
	}
	bool ME_IOConnectionContext::RemoveConenction(ME_IOConnection* Connection)
	{
		ME_TODO("Implement this!");
		return false;
	}



	ME_IOConnection::ME_IOConnection()
	{
		System			=	NULL;
		IContext		=	NULL;
		OContext		=	NULL;
		ConnectionId	=	0;
		IO				=	NULL;
		II				=	NULL;
		OI				=	NULL;
		OO				=	NULL;
		IO.IOConnection	=	this;
		II.IOConnection	=	this;
		OI.IOConnection	=	this;
		OO.IOConnection	=	this;
		State			=	0;
		Mode			=	0;
		Command			=	0;
		ORanges			=	CreateList(0);
		IRanges			=	CreateList(0);
		IsThinking		=	false;

		if (!InitializeCriticalSectionAndSpinCount(&Lock_Think, 0x80000400) ) 
		{
			ME_UNDEFINED_BEHAVIOR("ME_IOConnection::ME_IOConnection() couldn't initialize InitializeCriticalSectionAndSpinCount(&Lock_Think)!");
		}

	}

	ME_IOConnection::~ME_IOConnection()
	{
		DeleteList(ORanges);
		DeleteList(IRanges);
	}

	ME_IOThinkRequest::ME_IOThinkRequest()
	{
		for ( SIZE_T I = 0; I < ME_IOThinkRequest_Size; I++ )
		{
			List[I]		=	NULL;
		}
		Next			=	NULL;
	}


	SIZE_T	ME_IOConnection::IBufferRequired()
	{
		return 8192;
	}

	SIZE_T	ME_IOConnection::OBufferRequired()
	{
		return 8192;
	}

	SIZE_T	ME_IOConnection::IBufferSuggested()
	{
		return 8192;
	}

	SIZE_T	ME_IOConnection::OBufferSuggested()
	{
		return 8192;
	}

	int	ME_IOConnection::IPolicy()
	{
		return ME_IO_CTX_PERSONALBUFFER;
	}

	int	ME_IOConnection::OPolicy()
	{
		return ME_IO_CTX_PERSONALBUFFER;
	}

	int	ME_IOConnection::ORangePolicy()
	{
		return ME_IO_RANGES_UNDEFINED;
	}

	int	ME_IOConnection::IRangePolicy()
	{
		return ME_IO_RANGES_UNDEFINED;
	}

	
	bool			ME_IOConnection::AddORange(ME_IORange* Range)
	{
		ME_TODO("Implement this!");
		return false;
	}
	bool			ME_IOConnection::AddIRange(ME_IORange* Range)
	{
		ME_TODO("Implement this!");
		return false;
	}
	ME_IORange*		ME_IOConnection::GetORangeId(SIZE_T RangeId)
	{
		ME_TODO("Implement this!");
		return NULL;
	}
	ME_IORange*		ME_IOConnection::GetIRangeId(SIZE_T RangeId)
	{
		ME_TODO("Implement this!");
		return NULL;
	}
	ME_IORange*		ME_IOConnection::GetORangePos(Bytes_t Position)
	{
		ME_TODO("Implement this!");
		return NULL;
	}
	ME_IORange*		ME_IOConnection::GetIRangePos(Bytes_t Position)
	{
		ME_TODO("Implement this!");
		return NULL;
	}
	Bytes_t			ME_IOConnection::GetONextRangePos(Bytes_t Position)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	Bytes_t			ME_IOConnection::GetINextRangePos(Bytes_t Position)
	{
		ME_TODO("Implement this!");
		return 0;
	}

	bool	ME_IOConnection::Connect(ME_IOConnectionPointer* Remote)
	{
		if ( Remote == &II ) { return IIConnect(Remote); } else
		if ( Remote == &OO ) { return OOConnect(Remote); } else
		return false;
	}

	bool	ME_IOConnection::IIConnect(ME_IOConnectionPointer* Remote)
	{
		if ( II ) { return false; }

		LockThink();

		II.Other		=	Remote;
		Remote->Other	=	II;

		IIConnected();
		II->Connected(Remote);
		System->ConnectionEstablished(&II,Remote);

		UnlockThink();

		return true;
	}

	bool	ME_IOConnection::OOConnect(ME_IOConnectionPointer* Remote)
	{
		if ( OO ) { return false; }

		LockThink();

		OO.Other		=	Remote;
		Remote->Other	=	OO;

		OOConnected();
		OO->Connected(Remote);
		System->ConnectionEstablished(&OO,Remote);

		UnlockThink();

		return true;
	}

	bool	ME_IOConnection::Connected(ME_IOConnectionPointer* Connection)
	{
		if ( Connection == &II ) { return IIConnected(); } else
		if ( Connection == &IO ) { return IOConnected(); } else
		if ( Connection == &OI ) { return OIConnected(); } else
		if ( Connection == &OO ) { return OOConnected(); } else
		return false;
	}

	bool	ME_IOConnection::IIConnected()
	{
		return true;
	}

	bool	ME_IOConnection::IOConnected()
	{
		return true;
	}

	bool	ME_IOConnection::OIConnected()
	{
		return true;
	}

	bool	ME_IOConnection::OOConnected()
	{
		return true;
	}

	bool	ME_IOConnection::IIDisconnect()
	{
		LockThink();

		if ( IO )
		{
			IO->Disconnect(IO.Other);
			IO	=	NULL;
		}

		II->Disconnected(II);
		System->ConnectionInvalidated(&II,II.Other);
		II	=	NULL;
		IIDisconnected();

		if ( II == NULL && IO == NULL && OI == NULL && OO == NULL )
		{
			Disconnected();
		}

		UnlockThink();

		return true;
	}

	bool	ME_IOConnection::OODisconnect()
	{
		LockThink();

		if ( OI )
		{
			OI->Disconnect(OI.Other);
			OI	=	NULL;
		}

		OO->Disconnected(OO);
		System->ConnectionInvalidated(&OO,OO.Other);
		OO	=	NULL;
		OODisconnected();

		ME_DONT_COMPILE_RELEASE_BUILD();
		// Todo: Is the below correct, should we wait until all four
		// is disconnected before calling Disconnected() or just two
		// of them?

		if ( II == NULL && IO == NULL && OI == NULL && OO == NULL )
		{
			Disconnected();
		}

		UnlockThink();

		return true;
	}

	bool	ME_IOConnection::IIDisconnected()
	{
		return true;
	}

	bool	ME_IOConnection::IODisconnected()
	{
		return true;
	}

	bool	ME_IOConnection::OIDisconnected()
	{
		return true;
	}

	bool	ME_IOConnection::OODisconnected()
	{
		return true;
	}

	bool	ME_IOConnection::Disconnect()
	{
		IIDisconnect();
		OODisconnect();

		return true;
	}

	bool	ME_IOConnection::Disconnect(ME_IOConnectionPointer* Connection) // When Connection should be disconnected
	{
		ME_TODO("Implement this!");
		return false;
	}
		

	bool	ME_IOConnection::Disconnected()
	{
		return true;
	}

	bool	ME_IOConnection::Disconnected(ME_IOConnectionPointer* Connection)
	{
		// Around here we should check if all connections are null and then call Disconnected().
		ME_TODO("Implement this!");
		return false;
	}
		
	SIZE_T		ME_IOConnection::GetIBytesAvailable() // Returns the amount of bytes that can be sent through the input-channel at the moment
	{
		ME_TODO("Implement this!");
		return 0;
	}
	SIZE_T		ME_IOConnection::GetOBytesAvailable() // Returns the amount of bytes than can be sent through the output-channel at the moment
	{
		ME_TODO("Implement this!");
		return 0;
	}

	
	int		ME_IOConnection::SendInput(char* Buffer, SIZE_T BufferLen)
	{
		ME_TODO("Implement this!");
		return 0;
	}

	int		ME_IOConnection::SendInput(ME_Buffer* Buffer)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::SendOutput(char* Buffer, SIZE_T BufferLen)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::SendOutput(ME_Buffer* Buffer)
	{
		ME_TODO("Implement this!");
		return 0;
	}

	int		ME_IOConnection::IOUnavailable(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::IOWarning(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::IOComment(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::IOAssertionFailure(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}

	int		ME_IOConnection::OnIOUnavailable(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::OnIOWarning(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::OnIOComment(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	int		ME_IOConnection::OnIOAssertionFailure(ME_IOConnectionPointer* Connection, DWORD Error, char* ErrorMessage)
	{
		ME_TODO("Implement this!");
		return 0;
	}
	
	bool	ME_IOConnection::OnThink()
	{
		ME_UNDEFINED_BEHAVIOR("ME_IOConnection::OnThink() should be defined in child classes!");

		return false;
	}

	bool	ME_IOConnection::EvaluateConnection() // Return true if the connection still has something to do - return false if it has nothing to do and could be shut down with no harm.
	{
		ME_UNDEFINED_BEHAVIOR("ME_IOConnection::EvaluateConnection() should be defined in child classes!");

		return false;
	}

	
	bool	ME_IOConnection::ScheduledNextThink(int NextThinkType, int Line, char* Function, char* FileName)
	{
		ME_TODO("Implement this!");
		return false;
	}

	void	ME_IOConnection::DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
	{
		ME_TODO("Implement this!");

		RequestThink();
	}



	int		ME_IOConnection::OnInput(char* Buffer, SIZE_T BufferLen)
	{
		if ( Buffer == NULL || BufferLen == 0 || IContext == NULL || IContext->Buffer == NULL || II == NULL ) { return ME_IO_O_ASSERTIONFAILURE; }
		
		ME_Buffer*	IBuffer		=	IContext->Buffer;
		int			Result		=	ME_IO_O_WROTE;

		if ( II->IContext == IContext )
		{
			ME_UNDEFINED_BEHAVIOR("ME_IOConnection::Input(char* Buffer, size_t BufferLen) has no support for shared Contexts!");
			Result				=	ME_IO_O_HORRIBLEEVENT;
		}
		else
		{
			IBuffer->ME_BUFFER_LOCK_EX(ME_Buffer_Flag_Write);

			if ( BufferLen > IBuffer->GetBufferAvailable() )
			{
				if ( BufferLen > IBuffer->GetBufferSize() )
				{
					// Our buffer could never hold the buffer. (This shouldn't happen.)
					Result			=	ME_IO_O_NOTENOUGHMEMORY;
				}
				else
				{
					// We don't have enough space, at the time.
					// Make a callback next time any space has been cleared up -
					// that might do the trick, otherwise we might have to keep on trying.
					II.Flags		|=	ME_IO_FLAG_CHOKED;
					II.Other->Flags	|=	ME_IO_FLAG_CHOKED;

					Result			=	ME_IO_O_RETRY;
				}
			}
			else
			{
				// Write to our context buffer
				if ( IBuffer->Write(Buffer, BufferLen) != ME_ERROR_SUCCESS )
				{
					// Despite we assured that we have enough space, our write
					// failed, which shouldn't happen. This is an assertion.
					Result			=	ME_IO_O_HORRIBLEEVENT;
				}
				else
				{
					// Our write succeded, we are no longer choked, mark that.
					II.Flags		&=	~ME_IO_FLAG_CHOKED;
					II.Other->Flags	&=	~ME_IO_FLAG_CHOKED;
				}
			}

			IBuffer->Unlock();
		}

		RequestThink(); // Request a think. We'll get a callback when it's our turn.

		return Result;
	}

	int		ME_IOConnection::OnInput(ME_Buffer* Buffer)
	{
		if ( Buffer == NULL || IContext == NULL || IContext->Buffer == NULL || II == NULL ) { return ME_IO_O_ASSERTIONFAILURE; }
		
		ME_Buffer*	IBuffer		=	IContext->Buffer;
		int			Result		=	ME_IO_O_WROTE;

		if ( II->IContext == IContext )
		{
			//ME_UNDEFINED_BEHAVIOR("ME_IOConnection::Input(ME_Buffer* Buffer) has no support for shared Contexts!");
			//Result				=	ME_IO_O_HORRIBLEEVENT;
			// Todo: I think we can safely assume it worked.
			// I mean, we share the same buffer, and our read is done automatically,
			// we just have to read the data from the buffer in our mode.
		}
		else
		{
			Buffer->ME_BUFFER_LOCK_EX( ME_Buffer_Flag_Read );
			IBuffer->Lock( ME_BUFFER_LOCK_PARAMS );

			if ( Buffer->GetBufferUsed() > IBuffer->GetBufferAvailable() )
			{
				if ( Buffer->GetBufferUsed() > IBuffer->GetBufferSize() )
				{
					// Our buffer could never hold the buffer. (This shouldn't happen.)
					Result			=	ME_IO_O_NOTENOUGHMEMORY;
				}
				else
				{
					// We don't have enough space, at the time.
					// Make a callback next time any space has been cleared up -
					// that might do the trick, otherwise we might have to keep on trying.
					II.Flags		|=	ME_IO_FLAG_CHOKED;
					II.Other->Flags	|=	ME_IO_FLAG_CHOKED;

					Result			=	ME_IO_O_RETRY;
				}
			}
			else
			{
				// Write to our context buffer
				if ( IBuffer->Write(Buffer, Buffer->GetBufferUsed()) != ME_ERROR_SUCCESS )
				{
					// Despite we assured that we have enough space, our write
					// failed, which shouldn't happen. This is an assertion.
					Result			=	ME_IO_O_HORRIBLEEVENT;
				}
				else
				{
					// Our write succeded, we are no longer choked, mark that.
					II.Flags		&=	~ME_IO_FLAG_CHOKED;
					II.Other->Flags	&=	~ME_IO_FLAG_CHOKED;
				}
			}

			IBuffer->Unlock();
			Buffer->Unlock();
		}

		RequestThink(); // Request a think. We'll get a callback when it's our turn.

		return Result;
	}

	int		ME_IOConnection::OnOutput(char* Buffer, SIZE_T BufferLen)
	{
		if ( Buffer == NULL || BufferLen == 0 || OContext == NULL || OContext->Buffer == NULL || OO == NULL ) { return ME_IO_O_ASSERTIONFAILURE; }
		
		ME_Buffer*	OBuffer		=	OContext->Buffer;
		int			Result		=	ME_IO_O_WROTE;

		if ( OO->OContext == OContext )
		{
			ME_UNDEFINED_BEHAVIOR("ME_IOConnection::Output(char* Buffer, size_t BufferLen) has no support for shared Contexts!");
			Result				=	ME_IO_O_HORRIBLEEVENT;
		}
		else
		{
			OBuffer->ME_BUFFER_LOCK_EX(ME_Buffer_Flag_Write);

			if ( BufferLen > OBuffer->GetBufferAvailable() )
			{
				if ( BufferLen > OBuffer->GetBufferSize() )
				{
					// Our buffer could never hold the buffer. (This shouldn't happen.)
					Result			=	ME_IO_O_NOTENOUGHMEMORY;
				}
				else
				{
					// We don't have enough space, at the time.
					// Make a callback next time any space has been cleared up -
					// that might do the trick, otherwise we might have to keep on trying.
					OI.Flags		|=	ME_IO_FLAG_CHOKED;
					OI.Other->Flags	|=	ME_IO_FLAG_CHOKED;

					Result			=	ME_IO_O_RETRY;
				}
			}
			else
			{
				// Write to our context buffer
				if ( OBuffer->Write(Buffer, BufferLen) != ME_ERROR_SUCCESS )
				{
					// Despite we assured that we have enough space, our write
					// failed, which shouldn't happen. This is an assertion.
					Result			=	ME_IO_O_HORRIBLEEVENT;
				}
				else
				{
					// Our write succeded, we are no longer choked, mark that.
					OI.Flags		&=	~ME_IO_FLAG_CHOKED;
					OI.Other->Flags	&=	~ME_IO_FLAG_CHOKED;
				}
			}

			OBuffer->Unlock();
		}

		RequestThink(); // Request a think. We'll get a callback when it's our turn.

		return Result;
	}

	int		ME_IOConnection::OnOutput(ME_Buffer* Buffer)
	{
		if ( Buffer == NULL || OContext == NULL || OContext->Buffer == NULL || OO == NULL ) { return ME_IO_O_ASSERTIONFAILURE; }
		
		ME_Buffer*	OBuffer		=	IContext->Buffer;
		int			Result		=	ME_IO_O_WROTE;

		if ( OO->OContext == OContext )
		{
			//ME_UNDEFINED_BEHAVIOR("ME_IOConnection::Input(ME_Buffer* Buffer) has no support for shared Contexts!");
			//Result				=	ME_IO_O_HORRIBLEEVENT;
			// Todo: I think we can safely assume it worked.
			// I mean, we share the same buffer, and our read is done automatically,
			// we just have to read the data from the buffer in our mode.
		}
		else
		{
			Buffer->ME_BUFFER_LOCK_EX(ME_Buffer_Flag_Read);
			OBuffer->Lock( ME_BUFFER_LOCK_PARAMS );

			if ( Buffer->GetBufferUsed() > OBuffer->GetBufferAvailable() )
			{
				if ( Buffer->GetBufferUsed() > OBuffer->GetBufferSize() )
				{
					// Our buffer could never hold the buffer. (This shouldn't happen.)
					Result			=	ME_IO_O_NOTENOUGHMEMORY;
				}
				else
				{
					// We don't have enough space, at the time.
					// Make a callback next time any space has been cleared up -
					// that might do the trick, otherwise we might have to keep on trying.
					OI.Flags		|=	ME_IO_FLAG_CHOKED;
					OI.Other->Flags	|=	ME_IO_FLAG_CHOKED;

					Result			=	ME_IO_O_RETRY;
				}
			}
			else
			{
				// Write to our context buffer
				if ( OBuffer->Write(Buffer, Buffer->GetBufferUsed()) != ME_ERROR_SUCCESS )
				{
					// Despite we assured that we have enough space, our write
					// failed, which shouldn't happen. This is an assertion.
					Result			=	ME_IO_O_HORRIBLEEVENT;
				}
				else
				{
					// Our write succeded, we are no longer choked, mark that.
					OI.Flags		&=	~ME_IO_FLAG_CHOKED;
					OI.Other->Flags	&=	~ME_IO_FLAG_CHOKED;
				}
			}

			OBuffer->Unlock();
		}

		RequestThink(); // Request a think. We'll get a callback when it's our turn.

		return Result;
	}


	bool ME_IOConnection::LockThink()
	{
		EnterCriticalSection(&Lock_Think);
		return true;
	}
	
	bool ME_IOConnection::UnlockThink()
	{
		LeaveCriticalSection(&Lock_Think);
		return true;
	}

	bool ME_IOConnection::Think()
	{
		LockThink();

		if ( IsThinking )
		{
			ScheduleNextThink(ME_NEXT_THINK_THINKAGAIN);
			UnlockThink();
			return false; // Don't think now, however, a rethink is pending!
		}

		IsThinking	=	true;
		NextThink	=	ME_NEXT_THINK_THINKAGAIN;

		while ( NextThink == ME_NEXT_THINK_THINKAGAIN )
		{
			NextThink	=	ME_NEXT_THINK_NONE;

			OnThink();

			if ( NextThink == ME_NEXT_THINK_NONE )
			{
	#ifdef _DEBUG

				// Debug variables, eases finding where the bug happened

				int	CurrentMode		=	Mode;
				int	CurrentCommand	=	Command;	

	#endif
				ME_UNDEFINED_BEHAVIOR("ME_IOConnection::Think() had NextThink == ME_NEXT_THINK_NONE! There is a bug in the OnThink() function!");
			}
		}

		IsThinking	=	false;

		UnlockThink();

		return true;
	}

	bool ME_IOConnection::RequestThink()
	{
		if ( System )
		{
			return System->RequestThink(this);
		}
		else
		{
			return false;
		}
	}

	// ===============================================================================================
	//	ME_IOSystem
	// ===============================================================================================

	ME_IOSystem::ME_IOSystem()
	{
		if (!InitializeCriticalSectionAndSpinCount(&Lock_Connections, 0x80000400) ) 
		{
			ME_UNDEFINED_BEHAVIOR("ME_IOSystem::ME_IOSystem() couldn't initialize InitializeCriticalSectionAndSpinCount(&Lock_Connections)!");
		}
		if (!InitializeCriticalSectionAndSpinCount(&Lock_ThinkList, 0x80000400) ) 
		{
			ME_UNDEFINED_BEHAVIOR("ME_IOSystem::ME_IOSystem() couldn't initialize InitializeCriticalSectionAndSpinCount(&Lock_Connections)!");
		}
		Connections			=	CreateList(0);
	}

	ME_IOSystem::~ME_IOSystem()
	{
		DeleteCriticalSection(&Lock_Connections);
		DeleteCriticalSection(&Lock_ThinkList);
		DeleteList(Connections);
	}

	bool ME_IOSystem::RequestThink(ME_IOConnection* Thinkee)
	{
		EnterCriticalSection(&Lock_ThinkList);
			
		// Find us a clear spot in our think list!

		ME_IOThinkRequest*	pThinkList		=	&ThinkList;

		bool				ShouldQuitLoop	=	false;

		while ( ShouldQuitLoop == false )
		{
			for ( SIZE_T I = 0; I < ME_IOThinkRequest_Size; I++ )
			{
				if ( pThinkList->List[I] == NULL )
				{
					pThinkList->List[I]		=	Thinkee;
					ShouldQuitLoop			=	true;
					break;
				}
				if ( pThinkList->List[I] == Thinkee )
				{
					// Ooops! We are already pending. Just ignore this request. :-)
					ShouldQuitLoop			=	true;
					break;
				}
			}

			if ( pThinkList->Next == NULL )
			{
				pThinkList->Next			=	new ME_IOThinkRequest;
				pThinkList->Next->List[0]	=	Thinkee;
				ShouldQuitLoop				=	true;
			}
			else
			{
				pThinkList	=	pThinkList->Next;
			}			
		}

		LeaveCriticalSection(&Lock_ThinkList);

		return true;
	}

	bool ME_IOSystem::PerformThreadThinking()
	{
		// By now, we probably have a few connections needing to process
		// their input and do some outputtin', so let's get crackin'!

		// Using a thread-shared thread-safe array, we can automatically scale
		// each connection to the proper amount of threads/cores.

		// To get started, keep running through the array until all think slots
		// are NULL and we can return control to the OS. Of course, one think
		// might trigger some more thinks, so this *might* loop a bit, but
		// as long any network/filesystems are slower than the CPU, we should
		// finish and we can safely return control to the OS.

		ME_IOThinkRequest*		pThinkList		=	&ThinkList;
		ME_IOConnection*		Thinkee			=	NULL;
		bool					ShouldQuitLoop	=	false;

		// Call everybody!
		while ( ShouldQuitLoop == false )
		{
			pThinkList		=	&ThinkList;

			// Find a thinkee!
			EnterCriticalSection(&Lock_ThinkList);

			while ( pThinkList )
			{
				for ( unsigned int I = 0; I < ME_IOThinkRequest_Size; I++ )
				{
					if ( pThinkList->List[I] )
					{
						Thinkee					=	pThinkList->List[I]; // Remember who is going to think
						pThinkList->List[I]		=	NULL; // Delete that think request from the array, and leave room for another think.
						break;
					}
				}
				if ( Thinkee ) { break; }

				pThinkList	=	pThinkList->Next;
			}

			LeaveCriticalSection(&Lock_ThinkList);

			if ( Thinkee )
			{
				Thinkee->Think();
			}
			else
			{
				ShouldQuitLoop = true; // We finally processed all the thinking required, return control to the OS.
			}
		}
		
		return true;
	}

	bool ME_IOSystem::Lock()
	{
		EnterCriticalSection(&Lock_Connections);
		return true;
	}

	bool ME_IOSystem::Unlock()
	{
		EnterCriticalSection(&Lock_Connections);
		return true;
	}

	ME_IOConnection*	ME_IOSystem::CreateConnection(char* ConnectionType)
	{
		// HACK!
		ME_DONT_COMPILE_RELEASE_BUILD();

		if ( _stricmp(ConnectionType,"ME_FileSystem") == 0 )
		{
			return new ME_IOFileSystem;
		} else
		if ( _stricmp(ConnectionType,"ME_IOConnectionFeed") == 0 )
		{
			return new ME_IOConnectionFeed;
		}
		

		ME_TODO("Implement this!");
		return NULL;
	}

	bool	ME_IOSystem::ConnectionEstablished(ME_IOConnectionPointer* First, ME_IOConnectionPointer* Second)
	{
		ME_TODO("Implement this!");
		return false;
	}
	bool	ME_IOSystem::ConnectionInvalidated(ME_IOConnectionPointer* First, ME_IOConnectionPointer* Second)
	{
		ME_TODO("Implement this!");
		return false;
	}
	bool	ME_IOSystem::ConnectionTerminated(ME_IOConnectionPointer* First, ME_IOConnectionPointer* Second)
	{
		ME_TODO("Implement this!");
		return false;
	}

	ME_IOConnection*	ME_IOSystem::GetConnection(SIZE_T ConnectionId)
	{
		ME_TODO("Implement this!");
		return NULL;
	}
	
	SIZE_T	ME_IOSystem::NumConnections()
	{
		ME_TODO("Implement this!");
		return 0;
	}

	SIZE_T	ME_IOSystem::AddConnection(ME_IOConnection* Connection)
	{
		ME_TODO("Implement this!");
		return 0;
	}

	bool	ME_IOSystem::AddISpeed(Speed_t Amount)
	{
		ME_TODO("Implement this!");
		return false;
	}

	bool	ME_IOSystem::AddOSpeed(Speed_t Amount)
	{
		ME_TODO("Implement this!");
		return false;
	}
	
	bool	ME_IOSystem::CreateConnections()
	{
		ME_TODO("Implement this!");
		return false;
	}

	bool	ME_IOSystem::DeleteConnections()
	{
		ME_TODO("Implement this!");
		return false;
	}

	bool	ME_IOSystem::MainLoop()
	{
		ME_TODO("Implement this!");
		return false;
	}

	bool	ME_IOSystem::Feed(ME_IOConnectionPointer* Connection, char* Buffer, SIZE_T BufferLen, ME_IORange* Ranges, SIZE_T NumRanges)
	{
		if ( !Connection || !Buffer || BufferLen == 0 || !Connection->IOConnection ) { return false; }
		
		bool	Result		=	true;

		Connection->IOConnection->LockThink();

		ME_IOConnectionFeed*	Feed	=	(ME_IOConnectionFeed*)CreateConnection("ME_IOConnectionFeed");

		if ( Feed == NULL ) { Result = false; } else
		{
			Feed->LockThink();

			Feed->OutputBuffer			=	Buffer;
			Feed->OutputBufferLength	=	BufferLen;
			Feed->OutputBufferSent		=	0;

			Connection->IOConnection->Connect(&Feed->OO);

			ME_TODO("Implement more stuff here!");
			
			Feed->UnlockThink();
		}
		
		Connection->IOConnection->UnlockThink();
		
		return Result;
	}

	bool	SyncWriteFile(char* FileName, char* Buffer, SIZE_T BufferLen, Bytes_t Offset)
	{
		ME_IOSystem*		System		=	new ME_IOSystem;		
		ME_IOConnection*	Connection	=	System->CreateConnection("ME_FileSystem");
		ME_IORange*			Range		=	new ME_IORange;
		
		Range->Start					=	0;
		Range->End						=	BufferLen;
		Range->FileName					=	FileName;
		Range->Offset					=	Offset;

		System->Feed(Connection->II, Buffer, BufferLen, Range, 1);

		while ( System->MainLoop() ) { }

		delete Range;
		delete System;

		return true;
	}

	// ===============================================================================================
	//	ME_IOConnectionFeed
	// ===============================================================================================

	ME_IOConnectionFeed::ME_IOConnectionFeed()
	{
		OutputBuffer		=	NULL;
		OutputBufferSent	=	0;
		OutputBufferLength	=	0;
	}
	
	ME_IOConnectionFeed::~ME_IOConnectionFeed()
	{
		delete[] OutputBuffer;
	}

	SIZE_T ME_IOConnectionFeed::IBufferRequired()
	{
		return 0;
	}

	SIZE_T ME_IOConnectionFeed::OBufferRequired()
	{
		return 0;
	}

	SIZE_T ME_IOConnectionFeed::IBufferSuggested()
	{
		return 0;
	}

	SIZE_T ME_IOConnectionFeed::OBufferSuggested()
	{
		return 0;
	}

	int ME_IOConnectionFeed::OPolicy()
	{
		return ME_IO_CTX_NOBUFFER;
	}

	int ME_IOConnectionFeed::IPolicy()
	{
		return ME_IO_CTX_NOTCONNECTABLE;
	}

	int ME_IOConnectionFeed::ORangePolicy()
	{
		return ME_IO_RANGES_SUPPORTED;
	}

	int ME_IOConnectionFeed::IRangePolicy()
	{
		return ME_IO_RANGES_UNDEFINED;
	}

	bool ME_IOConnectionFeed::OnThink()
	{
		if ( !OO ) { return false; }
		if ( !OutputBuffer ) { return false; }
		if ( OutputBufferLength == 0 ) { return false; }
		if ( OutputBufferSent == OutputBufferLength ) { return false; }

		bool	ShouldKeepWriting	=	true;
		bool	Result				=	true;

		while ( ShouldKeepWriting )
		{
			OO->LockThink();
			SIZE_T	Possible	=	OO.GetBytesAvailable();

			// How much data do we have, compared to the amount we can send.
			if ( Possible > OutputBufferLength-OutputBufferSent )
			{
				Possible = OutputBufferLength-OutputBufferSent;
			}
			
			int		Result		=	SendOutput(OutputBuffer+OutputBufferSent, Possible);

			if ( Result == ME_IO_O_WROTE ) // Yes, we can!
			{
				OutputBufferSent	+=	Possible;

				if ( OutputBufferSent == OutputBufferLength )
				{
					ScheduleNextThink(ME_NEXT_THINK_DONT);
					ShouldKeepWriting	=	false;

					Result				=	false; // Shut down here.
				}
				else
				{
					// There is still some data, left keep trying!
				}
			}
			else if ( Result == ME_IO_O_RETRY )
			{
				// Whoops. We failed. We'll be called next time there is any buffer left.
				ScheduleNextThink(ME_NEXT_THINK_MECALLBACK);
				ShouldKeepWriting	=	false;
			}
			else if ( Result == ME_IO_O_HORRIBLEEVENT || Result == ME_IO_O_ASSERTIONFAILURE )
			{
				ShouldKeepWriting	=	false;
				Result				=	false; // Shut down here.
				ScheduleNextThink(ME_NEXT_THINK_DONT);
			}
			else if ( Result == ME_IO_O_NOTENOUGHMEMORY )
			{
				// This is interested. We asked how much memory was available and it wasn't
				// anyways. Interesting. What to do now?
				ShouldKeepWriting	=	false;
				Result				=	false; // Shut down here.
				ScheduleNextThink(ME_NEXT_THINK_DONT);
			}
			else
			{
				// Forget what I said above, this case is much more interesting.
				ShouldKeepWriting	=	false;
				Result				=	false; // Shut down here.
				ScheduleNextThink(ME_NEXT_THINK_DONT);
			}

			OO->UnlockThink();
		}

		return Result;		
	}
	
	bool ME_IOConnectionFeed::AddORange(ME_IORange* Range)
	{
		if ( !OO ) { return false; }
		return OO->AddORange(Range);
	}

	bool ME_IOConnectionFeed::EvaluateConnection()
	{
		if ( !OO ) { return false; }
		if ( !OutputBuffer ) { return false; }
		if ( OutputBufferLength == 0 ) { return false; }
		if ( OutputBufferSent == OutputBufferLength ) { return false; }

		return true;
	}

	char* GetWinErrorMessage(DWORD ErrorCode)
	{
		char*	Temporary;
		DWORD	Success		=	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, ErrorCode, LANG_NEUTRAL, (LPSTR)&Temporary, 0, NULL);

		if ( Success ) 
		{
			char*	Result	=	BuildString(1,Temporary);
			LocalFree(Temporary);
			return Result;
		}
		else
		{
			ME_UNDEFINED_BEHAVIOR("FormatMessageA() failed in GetWinErrorMessage()!");
			return NULL;
		}
	}

	void CALLBACK	ME_IOConnection__DoneIO(DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
	{
		((ME_OVERLAPPED*)(lpOverlapped))->IOConnection->IOConnection->DoneIO(dwErrorCode, dwNumberOfBytesTransferred, lpOverlapped);
	}


	HANDLE*				MaxsiIOWorkerThreads				=	NULL;
	HANDLE				MaxsiIOWorkerThreadHasWork			=	NULL;
	bool				MaxsiIOWorkerThreadShouldMainLoop	=	true;
	CRITICAL_SECTION	MaxsiIOWorkerThreadLock;

	DWORD_PTR WINAPI MaxsiIOWorkerThread(void* p)
	{	
		DWORD	MaintenanceTime		=	20000;

		while (MaxsiIOWorkerThreadShouldMainLoop)
		{
			DWORD Result = MsgWaitForMultipleObjectsEx (1,&MaxsiIOWorkerThreadHasWork,(DWORD)MaintenanceTime,QS_ALLPOSTMESSAGE,MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);

			if ( Result == WAIT_OBJECT_0 )
			{
				EnterCriticalSection(&MaxsiIOWorkerThreadLock);

				// Do IO work here!

				LeaveCriticalSection(&MaxsiIOWorkerThreadLock);
			}
			else if ( Result == WAIT_TIMEOUT )
			{
				// Maintain stuff here!
			}
			else if ( Result == WAIT_OBJECT_0 + 1 )
			{
				MSG		msg			=	{0};
				GetMessage( &msg, NULL, 0, 0 );
				TranslateMessage(&msg);
				DispatchMessage(&msg); 
			}
			else
			{
				break;
			}
		}


		return 0;
	}

	
	LINK	DWORD_PTR				GetNumberOfLogicalCPUs()
	{
		SYSTEM_INFO m_si;
		GetSystemInfo(&m_si);
		return (DWORD_PTR)m_si.dwNumberOfProcessors;
	}

	LINKCPP	bool					MaxsiIOCreateWorkerThreads()
	{
		if ( MaxsiIOWorkerThreads ) { return true; } // Already is created.

		MaxsiIOWorkerThreadHasWork	=	CreateEvent(0, true, false, NULL);
		// Where should we close the handle? //if ( MaxsiIOWorkerThreadHasWork ) { CloseHandle(MaxsiIOWorkerThreadHasWork); }

		if (!InitializeCriticalSectionAndSpinCount(&MaxsiIOWorkerThreadLock, 0x80000400) ) 
		{
			ME_UNDEFINED_BEHAVIOR("MaxsiIOCreateWorkerThreads() couldn't initialize InitializeCriticalSectionAndSpinCount(&MaxsiIOWorkerThreadLock)!");
		}

		DWORD_PTR	NumThreads		=	GetNumberOfLogicalCPUs();
		
		// Avoid overflows in the affinity bit mask.
#if defined(_WIN64)
		if ( NumThreads >= 64 ) { NumThreads = 64-1; }
#else
		if ( NumThreads >= 32 ) { NumThreads = 32-1; }
#endif
		MaxsiIOWorkerThreads = new HANDLE[NumThreads];

		for(DWORD_PTR i = 0; i < NumThreads; i++)
		{
			DWORD_PTR m_id = i;
			DWORD_PTR m_mask = 1 << i;

			MaxsiIOWorkerThreads[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MaxsiIOWorkerThread, (LPVOID)i, (DWORD)NULL, &m_id);
			// Performance might improve with this on, during heavy load from only this program, 
			// but on low load, it might make it worse.
			SetThreadAffinityMask(MaxsiIOWorkerThreads[i], m_mask); 
		}

		return true;
	}
	

}
#endif
